import tkinter as tk
from tkinter import filedialog, messagebox, ttk

import matplotlib
import ttkbootstrap as ttk
from ttkbootstrap.constants import *

from app.util.annotation_util import annotate, ClassInfo

matplotlib.use('TkAgg')  # 使用Tkinter后端
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
from matplotlib.figure import Figure
import trimesh
import numpy as np
import os

from app.view.base_view import View


@annotate(ClassInfo(name="3DView", category="tool"))
class TdView(View):
    def __init__(self, parent, controller):
        super().__init__(parent, controller)
        # 初始化变量
        self.current_file = None
        self.mesh = None
        self.fig = None
        self.ax = None
        self.canvas = None
        self.rotation_angle = [30, 45]  # 初始旋转角度
        self.zoom_level = 1.0
        self.pan_offset = [0, 0]
        self.is_rotating = False
        self.is_panning = False
        self.last_mouse_pos = (0, 0)

        # 创建UI
        self._create_widgets()

    def _create_widgets(self):
        # 主容器
        main_container = ttk.Frame(self, padding=10)
        main_container.pack(fill=BOTH, expand=YES)

        # 顶部控制栏
        control_frame = ttk.LabelFrame(main_container, text="控制", padding=10)
        control_frame.pack(fill=X, pady=5)

        # 文件操作按钮
        file_frame = ttk.Frame(control_frame)
        file_frame.pack(side=LEFT, padx=5)

        ttk.Button(
            file_frame,
            text="打开文件",
            command=self.open_file,
            bootstyle=PRIMARY,
            width=12
        ).pack(side=LEFT, padx=5)

        ttk.Button(
            file_frame,
            text="重置视图",
            command=self.reset_view,
            bootstyle=SECONDARY,
            width=12
        ).pack(side=LEFT, padx=5)

        # 视图信息
        self.info_var = tk.StringVar(value="未加载文件")
        ttk.Label(
            control_frame,
            textvariable=self.info_var,
            font=("Arial", 10)
        ).pack(side=LEFT, padx=20)

        # 操作模式选择
        mode_frame = ttk.Frame(control_frame)
        mode_frame.pack(side=RIGHT, padx=5)

        self.interaction_mode = tk.StringVar(value="rotate")
        ttk.Radiobutton(
            mode_frame,
            text="旋转",
            variable=self.interaction_mode,
            value="rotate"
        ).pack(side=LEFT, padx=5)

        ttk.Radiobutton(
            mode_frame,
            text="平移",
            variable=self.interaction_mode,
            value="pan"
        ).pack(side=LEFT, padx=5)

        ttk.Radiobutton(
            mode_frame,
            text="缩放",
            variable=self.interaction_mode,
            value="zoom"
        ).pack(side=LEFT, padx=5)

        # 3D视图区域
        view_frame = ttk.LabelFrame(main_container, text="3D视图", padding=10)
        view_frame.pack(fill=BOTH, expand=YES, pady=5)

        # 创建Matplotlib视图
        self.create_matplotlib_view(view_frame)

        # 底部操作按钮
        action_frame = ttk.LabelFrame(main_container, text="快捷操作", padding=10)
        action_frame.pack(fill=X, pady=5)

        # 预设视角按钮
        ttk.Button(
            action_frame,
            text="前视图",
            command=lambda: self.set_view_angle(0, 0),
            bootstyle=INFO,
            width=10
        ).pack(side=LEFT, padx=5)

        ttk.Button(
            action_frame,
            text="侧视图",
            command=lambda: self.set_view_angle(0, 90),
            bootstyle=INFO,
            width=10
        ).pack(side=LEFT, padx=5)

        ttk.Button(
            action_frame,
            text="顶视图",
            command=lambda: self.set_view_angle(90, 0),
            bootstyle=INFO,
            width=10
        ).pack(side=LEFT, padx=5)

        ttk.Button(
            action_frame,
            text="等轴测",
            command=lambda: self.set_view_angle(30, 45),
            bootstyle=INFO,
            width=10
        ).pack(side=LEFT, padx=5)

        # 分隔线
        ttk.Separator(action_frame, orient=VERTICAL).pack(side=LEFT, padx=10, fill=Y)

        # 缩放控制
        zoom_frame = ttk.Frame(action_frame)
        zoom_frame.pack(side=LEFT, padx=5)

        ttk.Button(
            zoom_frame,
            text="放大",
            command=self.zoom_in,
            bootstyle=SECONDARY,
            width=8
        ).pack(side=LEFT, padx=2)

        ttk.Button(
            zoom_frame,
            text="缩小",
            command=self.zoom_out,
            bootstyle=SECONDARY,
            width=8
        ).pack(side=LEFT, padx=2)

        # 显示选项
        self.show_edges = tk.BooleanVar(value=True)
        ttk.Checkbutton(
            action_frame,
            text="显示边",
            variable=self.show_edges,
            command=self.update_display
        ).pack(side=LEFT, padx=10)

        self.show_axes = tk.BooleanVar(value=True)
        ttk.Checkbutton(
            action_frame,
            text="显示坐标轴",
            variable=self.show_axes,
            command=self.toggle_axes
        ).pack(side=LEFT, padx=10)

    def create_matplotlib_view(self, parent):
        """创建Matplotlib 3D视图"""
        # 创建图形和轴
        self.fig = Figure(figsize=(8, 6), dpi=100)
        self.ax = self.fig.add_subplot(111, projection='3d')
        self.ax.set_facecolor('black')
        self.fig.patch.set_facecolor('#2d2d2d')

        # 初始文本
        self.ax.text(0, 0, 0, "请打开STEP/STP文件", color='white', fontsize=12, ha='center')

        # 创建画布并添加到Tkinter窗口
        self.canvas = FigureCanvasTkAgg(self.fig, master=parent)
        self.canvas.get_tk_widget().pack(fill=BOTH, expand=YES)

        # 绑定鼠标事件
        self.canvas.mpl_connect('button_press_event', self.on_mouse_press)
        self.canvas.mpl_connect('button_release_event', self.on_mouse_release)
        self.canvas.mpl_connect('motion_notify_event', self.on_mouse_move)
        self.canvas.mpl_connect('scroll_event', self.on_mouse_scroll)

    def open_file(self):
        """打开STEP/STP文件"""
        file_path = filedialog.askopenfilename(
            title="选择STEP/STP文件",
            filetypes=[
                ("STEP files", "*.step *.stp"),
                ("All files", "*.*")
            ]
        )

        if file_path and os.path.exists(file_path):
            try:
                # 读取STEP文件
                self.current_file = file_path
                self.mesh = trimesh.load(file_path)

                # 重置视图参数
                self.rotation_angle = [30, 45]
                self.zoom_level = 1.0
                self.pan_offset = [0, 0]

                # 更新显示
                self.update_display()

                # 更新信息
                file_name = os.path.basename(file_path)
                self.info_var.set(f"已加载: {file_name} (三角形: {len(self.mesh.triangles)})")
                messagebox.showinfo("成功", f"已成功加载文件: {file_name}")

            except Exception as e:
                messagebox.showerror("错误", f"无法加载文件: {str(e)}")
                self.current_file = None
                self.mesh = None

    def update_display(self):
        """更新3D显示"""
        if not self.mesh:
            return

        # 清除当前轴
        self.ax.clear()
        self.ax.set_facecolor('black')

        # 获取网格数据
        vertices = self.mesh.vertices
        triangles = self.mesh.faces

        # 应用平移
        vertices = vertices.copy()
        center = np.mean(vertices, axis=0)
        vertices -= center  # 居中模型

        # 绘制3D模型
        if self.show_edges.get():
            self.ax.plot_trisurf(
                vertices[:, 0], vertices[:, 1], vertices[:, 2],
                triangles=triangles,
                color='lightblue',
                edgecolor='white',
                linewidth=0.2,
                alpha=0.8
            )
        else:
            self.ax.plot_trisurf(
                vertices[:, 0], vertices[:, 1], vertices[:, 2],
                triangles=triangles,
                color='lightblue',
                alpha=0.8
            )

        # 设置视角
        self.ax.view_init(elev=self.rotation_angle[0], azim=self.rotation_angle[1])

        # 应用缩放
        self.ax.set_xlim3d(-self.zoom_level, self.zoom_level)
        self.ax.set_ylim3d(-self.zoom_level, self.zoom_level)
        self.ax.set_zlim3d(-self.zoom_level, self.zoom_level)

        # 隐藏刻度
        self.ax.set_xticks([])
        self.ax.set_yticks([])
        self.ax.set_zticks([])

        # 显示或隐藏坐标轴
        self.toggle_axes(force_update=True)

        # 刷新画布
        self.canvas.draw()

    def reset_view(self):
        """重置视图"""
        self.rotation_angle = [30, 45]
        self.zoom_level = 1.0
        self.pan_offset = [0, 0]
        self.update_display()

    def set_view_angle(self, elev, azim):
        """设置视图角度"""
        self.rotation_angle = [elev, azim]
        self.update_display()

    def zoom_in(self):
        """放大视图"""
        self.zoom_level *= 0.8
        self.update_display()

    def zoom_out(self):
        """缩小视图"""
        self.zoom_level *= 1.2
        self.update_display()

    def toggle_axes(self, force_update=False):
        """切换坐标轴显示"""
        if force_update or hasattr(self, 'ax'):
            if self.show_axes.get():
                self.ax.set_axis_on()
            else:
                self.ax.set_axis_off()

    def on_mouse_press(self, event):
        """处理鼠标按下事件"""
        if event.inaxes != self.ax:
            return

        self.last_mouse_pos = (event.x, event.y)

        mode = self.interaction_mode.get()
        if mode == "rotate":
            self.is_rotating = True
        elif mode == "pan":
            self.is_panning = True

    def on_mouse_release(self, event):
        """处理鼠标释放事件"""
        self.is_rotating = False
        self.is_panning = False

    def on_mouse_move(self, event):
        """处理鼠标移动事件"""
        if event.inaxes != self.ax:
            return

        if self.is_rotating:
            # 计算旋转角度变化
            dx = event.x - self.last_mouse_pos[0]
            dy = event.y - self.last_mouse_pos[1]

            # 更新旋转角度
            self.rotation_angle[1] += dx * 0.5  # 方位角
            self.rotation_angle[0] = max(0, min(180, self.rotation_angle[0] - dy * 0.5))  # 仰角

            # 更新显示
            self.update_display()

            # 更新鼠标位置
            self.last_mouse_pos = (event.x, event.y)

        elif self.is_panning and self.mesh:
            # 这里可以实现平移功能，需要更复杂的计算
            pass

    def on_mouse_scroll(self, event):
        """处理鼠标滚轮事件"""
        if event.inaxes != self.ax:
            return

        # 滚轮向上为正，向下为负
        if event.step > 0:
            self.zoom_in()
        else:
            self.zoom_out()

    def create_widgets(self):
        pass
